package ldh.im.base.handler;

import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import ldh.im.ImConfig;
import ldh.im.base.ImSession;
import ldh.im.base.SessionManager;
import ldh.im.base.service.AuthAbleService;
import ldh.im.dto.base.ErrorResp;
import ldh.im.util.ByteUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;

@ChannelHandler.Sharable
public class ImServerCheckHandler extends ChannelInboundHandlerAdapter {

    private static final Logger LOGGER = LoggerFactory.getLogger(ImServerCheckHandler.class);
    private static final int HEAD_LENGTH = 1 + ImConfig.SERVER_AUTH_LENGTH + ImConfig.VO_LENGTH;
    private static final byte AUTHED = 0b01110000;

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (!(msg instanceof ByteBuf)) {
            ctx.fireChannelRead(msg);
            return;
        }
        ByteBuf byteBuf = (ByteBuf) msg;
        if (byteBuf.readableBytes() > 1) {
            boolean checkVersion = checkVersion(ctx, byteBuf);
            if (!checkVersion) return;
        }
        if (byteBuf.readableBytes() >= HEAD_LENGTH+2) {
            int authCode = byteBuf.getInt(1);
            short vo = byteBuf.getShort(HEAD_LENGTH-2);
            boolean checkAuth = checkAuth(ctx.channel(), authCode);
            if (!checkAuth) {
                error(ctx, vo,101,"错误");
                return;
            }
            int length = byteBuf.getInt(HEAD_LENGTH);
            if (length < 1) {
                error(ctx, vo,102,"错误");
                return;
            }
        }
//        byteBuf.setByte(0, AUTHED);
        ctx.fireChannelRead(byteBuf);
    }

    private boolean checkAuth(Channel channel, int code) {
        if (AuthAbleService.getInstance().isNoAuth(code)) return true;
        ImSession session = SessionManager.getInstance().getImSession(channel);
        if (session == null) return false;
        Integer auth = (Integer) session.get(ImConfig.AUTH_CODE);
        if(auth == null) return false;
        return auth == code;
    }

    protected boolean checkImHeader(byte b) {
        int lowValue = ByteUtil.getLowFour(b);
        return lowValue == ImConfig.CLIENT_CODE;
    }

    private boolean checkVersion(ChannelHandlerContext ctx, ByteBuf byteBuf) {
        byte b = byteBuf.getByte(0);
        boolean isCheck = ByteUtil.getHighFour(b) == AUTHED;
        if (isCheck) return true;

        boolean checkIm = checkImHeader(b);  // 验证是否是客户端连接服务器
        if (!checkIm) {
            return false;
        }
        return true;
    }

    private void error(ChannelHandlerContext ctx, Short vo, int status,  String message) {
        InetSocketAddress inetSocketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        LOGGER.error("非法请求, ip: {}, vo: {}", inetSocketAddress.getAddress(), vo);
        ErrorResp errorRec = new ErrorResp(status, message);
        ChannelFuture future = ctx.channel().writeAndFlush(errorRec);
        future.addListener(ChannelFutureListener.CLOSE);
    }
}